#pragma once

#include <boostext/util/make_shared.hpp>
#include <QtCore/QString>
#include <boostext/iostreams/bin_ostream.hpp>
#include <boostext/iostreams/bin_istream.hpp>

#include "exports.hpp"
#include "pointer.hpp"
#include "Function.hpp"

#undef interface




namespace Engine
{
	namespace Script
	{
		class ENGINE_SCRIPT_API Reflectable;

		/**
		 * This class is a small wrapper around asIObjectType.
		 */
		class ENGINE_SCRIPT_API Type
		{
		public:

			typedef boost::optional<Type>   opt;

			/**
			 * Creates a Type wrapper, identifying an object type.
			 */
			Type(boost::weak_ptr<const Reflectable> reflectable, pointer<asIObjectType> objectType);

			/**
			 * Creates a Type wrapper, identifying a pod type.
			 */
			Type(boost::weak_ptr<const Reflectable> reflectable, int typeId);
			virtual ~Type();



			/** 
			 * @returns the type id
			 */
			int id() const;

			/**
			 * @returns the name of the type
			 */
			virtual QString name() const;

			/**
			 * @returns the size of this type in bytes
			 */
			virtual std::size_t size() const;

			/**
			 * Tests if this variable is a pod type.
			 */
			virtual bool isPod() const;



			/**
			 * @returns the value of the given variable
			 * @warning   If the data behind the given pointer is not of the given type,
			 *            then this function holds the right to fail horribly,
			 *            crash in your face and erase your harddrive.
			 */
			virtual QString value(const void* data) const;

			/**
			 * Tests if this type has a base or not.
			 */
			bool hasBase() const;

			/**
			 * @returns the base type of this one
			 */
			Type::opt base() const;

			/**
			 * Tests if this type implements an interface or not.
			 */
			int interfaceCount() const;

			/**
			 * @returns the nth interface
			 * @throws when index is bigger or equal to interfaceCount
			 */
			Type interface(int index) const;

			/**
			 * @returns the number of methods of this type
			 */
			int methodCount() const;

			/**
			 * @returns the nth method
			 * @throws when index is bigger or equal to methodCount
			 */
			Function method(int index) const;

			/**
			 * @returns the number of properties of this type
			 */
			int propertyCount() const;

			/**
			 * @returns the nth property
			 * @throws when index is bigger or equal to propertyCount
			 * @throws when this is a pod type
			 */
			Type property(int index) const;



			/**
			 * Compares this types state agains the one in the given stream
			 * and throws if there are differences.
			 */
			void compareState(boostext::iostreams::bin_istream& stream) const;

			/**
			 * Serializes most relevant information of this type.
			 */
			void saveState(boostext::iostreams::bin_ostream& stream) const;

		protected:

			/**
			 * @returns a pointer to the reflectable storage
			 */
			boost::shared_ptr<const Reflectable> reflectable() const;

		private:

			#pragma warning (push)
			#pragma warning (disable: 4251)
			boost::weak_ptr<const Reflectable>   m_reflectable;
			#pragma warning (pop)

			int                                  m_typeId;
			pointer<asIObjectType>               m_objectType; //< Empty for POD types
		};
		///////////////////////////////////////////////////////////////////////////////////////////
	}
	///////////////////////////////////////////////////////////////////////////////////////////////
}
///////////////////////////////////////////////////////////////////////////////////////////////////

ENGINE_SCRIPT_API boostext::iostreams::bin_istream& operator>>(boostext::iostreams::bin_istream& stream, QByteArray& data);
ENGINE_SCRIPT_API boostext::iostreams::bin_ostream& operator<<(boostext::iostreams::bin_ostream& stream, const QByteArray& data);
